package middleware

import (
	"context"
	"encoding/json"
	"fmt"
	"go_web/internal/global"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"log"
	"sort"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"github.com/samber/lo"
)

func LoginAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.Request.Header.Get("Authorization")
		fmt.Println("authHeader", authHeader)
		if authHeader == "" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		// 提取 Token 字符串
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		token := parts[1]
		// 先判断是否被正常登记过 redis 中
		redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", token))
		if redisRet.Err() == redis.Nil {
			if utils.ContainsString(redisRet.Err().Error(), "redis: nil") {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("该Token可能已过期"))
			}
			c.Abort()
			return
		}
		claims, err := utils.ValidateAccessToken(token)
		if err != nil {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
			c.Abort()
			return
		}

		c.Set("userId", claims.UserId)
		c.Next()
	}
}

func RoleAuthMiddleware(roleList ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		// 提取 Token 字符串
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		token := parts[1]
		// 先判断是否被正常登记过 redis 中
		redisRet := global.Redis.Get(c, fmt.Sprintf("token::%s", token))
		if redisRet.Err() == redis.Nil {
			if utils.ContainsString(redisRet.Err().Error(), "redis: nil") {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("该Token可能已过期"))
			}
			c.Abort()
			return
		}
		claims, err := utils.ValidateAccessToken(token)
		if err != nil {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
			c.Abort()
			return
		}
		if len(roleList) > 0 {
			roleListAtToken, err := utils.GetRoleListByToken(c, token)
			if err != nil {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
				c.Abort()
				return
			}
			existMap := make(map[string]bool)
			for i := range roleListAtToken {
				existMap[roleListAtToken[i]] = true
			}
			flag := false // 默认是没有角色权限的
			for i := range roleList {
				if existMap[roleList[i]] {
					flag = true
					break
				}
			}
			if !flag {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("该用户无相关角色权限"))
				c.Abort()
				return
			}
		}

		fmt.Println("通过 RoleAuthMiddleware", c.Request.URL.Path)
		c.Set("userId", claims.UserId)
		c.Next()
	}
}

func DynamicAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		// 提取 Token 字符串
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
			c.Abort()
			return
		}
		token := parts[1]
		claims, err := utils.ValidateAccessToken(token)
		if err != nil {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
			c.Abort()
			return
		}

		// 请求URL
		reqUrl := c.Request.URL.Path
		dataScopeList, err := utils.GetDataScopeListByToken(c, token)
		if err != nil {
			c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
			c.Abort()
			return
		}

		// 1. 用户级别：必须优先判断
		userExplicitlyDenied := len(lo.Filter(dataScopeList, func(item model_sys.SysDataScope, index int) bool {
			// && reqUrl == item.ReqUrl && *item.IsAccess && item.TargetId == *claims.UserId
			return "USER" == item.TargetType && reqUrl == item.ReqUrl && item.TargetId == claims.UserId && item.IsAccess
		}))

		if userExplicitlyDenied > 0 {
			c.JSON(200, res.NewR[interface{}]().SetCode(403).SetData(nil).SetMsg("用户无访问权限（特殊）"))
			c.Abort()
			return
		}

		// 用户或角色 有访问权限（allow） 才能放行
		accessAllowed := len(lo.Filter(dataScopeList, func(item model_sys.SysDataScope, index int) bool {
			return reqUrl == item.ReqUrl && item.IsAccess
		}))

		if accessAllowed <= 0 {
			c.JSON(200, res.NewR[interface{}]().SetCode(403).SetData(nil).SetMsg("无访问权限"))
			c.Abort()
			return
		}

		fmt.Println("通过 DynamicAuthMiddleware => ", getOrgList(c, reqUrl, token, claims.UserId, dataScopeList, true))
		c.Set("userId", claims.UserId)
		c.Next()
	}
}

// 获取到组织ID 列表（我们会以 用户赋予的那个为优先级最大，因为可能出现特殊限制给某个用户的权限）
func getOrgList(c context.Context, reqUrl string, token string, userId int64, dataScopeList []model_sys.SysDataScope, isCache bool) []int64 {
	var dataScope *model_sys.SysDataScope = nil
	roleList, err := utils.GetRoleListByToken(c, token)
	if err != nil {
		fmt.Println(err.Error())
		roleList = []string{}
	}
	if isCache {
		// 先查角色的数据范围
		// 使用 MinBy 直接找到优先级最高的
		roleFiltered := lo.Filter(dataScopeList, func(scope model_sys.SysDataScope, _ int) bool {
			return scope.TargetType == "ROLE" &&
				scope.ReqUrl == reqUrl &&
				lo.Contains(roleList, scope.Role) &&
				scope.IsAccess
		})
		if len(roleFiltered) > 0 {
			sort.Slice(roleFiltered, func(i, j int) bool {
				return getScopePriority(roleFiltered[i].ScopeType) < getScopePriority(roleFiltered[j].ScopeType)
			})
		}
		var roleDataScope *model_sys.SysDataScope
		if len(roleFiltered) > 0 {
			roleDataScope = &roleFiltered[0]
		}

		// 查找用户数据范围
		userFiltered := lo.Filter(dataScopeList, func(scope model_sys.SysDataScope, _ int) bool {
			return scope.TargetType == "USER" &&
				scope.ReqUrl == reqUrl &&
				scope.TargetId == userId &&
				scope.IsAccess
		})

		// 使用 Go 原生 sort.Slice 进行排序
		if len(userFiltered) > 0 {
			sort.Slice(userFiltered, func(i, j int) bool {
				return getScopePriority(userFiltered[i].ScopeType) < getScopePriority(userFiltered[j].ScopeType)
			})
		}
		var userDataScope *model_sys.SysDataScope
		if len(userFiltered) > 0 {
			userDataScope = &userFiltered[0]
		}
		if userDataScope != nil {
			dataScope = userDataScope
		} else {
			dataScope = roleDataScope
		}
		if dataScope == nil {
			return []int64{}
		}
		switch dataScope.ScopeType {
		case "ALL":
			{
				res, err := utils.GetOrgIDListFromRedis()
				if err != nil {
					log.Printf(err.Error())
					return []int64{}
				}
				return res
			}
		case "CUSTOM":
			{
				var customOrgIds []int64
				err := json.Unmarshal([]byte(*dataScope.CustomOrgJson), &customOrgIds)
				if err != nil {
					// 处理错误，比如日志记录或返回空切片
					log.Printf("解析 CustomOrgJson 失败: %v", err)
					customOrgIds = []int64{} // 返回空切片
				}
				return customOrgIds
			}
		case "ORG_SUB":
			{
				res, err := utils.GetDataScopeOrgSubByToken(c, token)
				if err != nil {
					log.Println(err)
					return []int64{}
				}
				return res
			}
		case "ORG":
			{
				res, err := utils.GetDataScopeOrgByToken(c, token)
				if err != nil {
					log.Println(err)
					return []int64{}
				}
				return res
			}
		case "SELF":
			{
				return []int64{}
			}
		}
		return []int64{}
	}
	return []int64{}
}

// 获取优先级函数
func getScopePriority(scopeType string) int {
	// 根据scopeType返回优先级，数值越小优先级越高
	priorityMap := map[string]int{
		"ALL":    1,
		"DEPT":   2,
		"SELF":   3,
		"CUSTOM": 4,
	}
	if val, ok := priorityMap[scopeType]; ok {
		return val
	}
	return 999 // 默认低优先级
}

// 静态资源请求专门中间件
func StaticFileMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		staticReqUrl := c.Request.URL.Path
		fileIdStr := utils.ExtractLastPath(staticReqUrl, false)
		var fileId int64
		var err error
		if fileIdStr != "" {
			fileId, _ = strconv.ParseInt(fileIdStr, 10, 64)

		}
		var fileAuthList []*model_sys.SysFileAuth
		if fileId > 0 {
			fileAuthList, err = repo_sys.SysFileAuth.WithContext(c).Where(repo_sys.SysFileAuth.FileID.Eq(fileId)).Find()
			if err != nil {
				c.JSON(200, res.NewR[interface{}]().SetCode(500).SetData(nil).SetMsg(err.Error()))
				c.Abort()
				return
			}
		}
		if fileAuthList != nil && len(fileAuthList) > 0 {
			authHeader := c.Request.Header.Get("Authorization")
			if authHeader == "" {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
				c.Abort()
				return
			}
			// 提取 Token 字符串
			parts := strings.SplitN(authHeader, " ", 2)
			if len(parts) != 2 || parts[0] != "Bearer" {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg("未携带Token"))
				c.Abort()
				return
			}
			token := parts[1]
			userID, err := utils.GetUserIdFromToken(token)
			if err != nil {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
				c.Abort()
				return
			}
			// 先看用户
			userFileAuthList := lo.Filter(fileAuthList, func(item *model_sys.SysFileAuth, index int) bool {
				return "USER" == item.TargetType && item.TargetId == userID
			})
			var userFileAuth *model_sys.SysFileAuth = nil
			if userFileAuthList != nil && len(userFileAuthList) > 0 {
				userFileAuth = userFileAuthList[0]
			}
			// 用户级别不让你访问
			if userFileAuth != nil && !userFileAuth.IsAccess {
				c.JSON(200, res.NewR[interface{}]().SetCode(403).SetData(nil).SetMsg("该用户无访问权限"))
				c.Abort()
				return
			}
			// 再去看角色
			roleList, err := utils.GetRoleListByToken(c, token)
			if err != nil {
				c.JSON(200, res.NewR[interface{}]().SetCode(401).SetData(nil).SetMsg(err.Error()))
				c.Abort()
				return
			}
			var roleSet map[interface{}]struct{} = make(map[interface{}]struct{})
			if roleList != nil && len(roleList) > 0 {
				for i := range roleList {
					roleSet[roleList[i]] = struct{}{}
				}
			}

			roleFileAuthList := lo.Filter(fileAuthList, func(item *model_sys.SysFileAuth, index int) bool {
				_, ok := roleSet[item.Role]
				return "ROLE" == item.TargetType &&
					ok
			})
			if roleFileAuthList != nil && len(roleFileAuthList) > 0 {
				accessRoleFileAuthList := lo.Filter(roleFileAuthList, func(item *model_sys.SysFileAuth, index int) bool {
					return item.IsAccess
				})
				if accessRoleFileAuthList == nil || len(accessRoleFileAuthList) == 0 {
					c.JSON(200, res.NewR[interface{}]().SetCode(403).SetData(nil).SetMsg("无角色权限可以无访问该静态资源"))
					c.Abort()
					return
				}
			}

		}

		c.Next() // 没有特殊情况校验，直接通过
	}
}
